#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <GL/glut.h>

#include "new_types.h"

float xCam,yCam,zCam;
float distCam=5,angleThetaCam=0,anglePhiCam=0;

int Npart=0;
double3 *innPos;

void drawSystem()
{
  //Clear Color and Depth Buffers
  glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
  
  //Reset transformations
  glLoadIdentity();
  gluLookAt(xCam,yCam,zCam, 0,0,0, 0,1,0);
  
  //draw the box
  glColor3f(1,1,1);
  glutWireCube(1);
  
  //draw each ball
  for(int i=0;i<Npart;i++)
    {
      printf("Part %d\n",i);
      glPushMatrix();
      glTranslatef(innPos[i][0],innPos[i][1],innPos[i][2]);
      glutSolidSphere(0.01,10,10);
      glPopMatrix();
    }
  
  glutSwapBuffers();
}

void plotGas(int N,double3 *x)
{
  Npart=N;
  innPos=x;
  glutPostRedisplay();
}

void changeSize(int w,int h)
{
  if(h==0) h=1;
  float ratio= w*1.0/h;
  
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  glViewport(0,0,w,h);
  gluPerspective(45,ratio,0.1,100);
  glMatrixMode(GL_MODELVIEW);
}

//update the position of the camera
void updateCamera()
{
  float distXzCam=distCam*cos(anglePhiCam);
  
  xCam=distXzCam*sinf(angleThetaCam);
  yCam=distCam*sinf(anglePhiCam);
  zCam=distXzCam*cosf(angleThetaCam);
}

//rotate the camera to the left
void rotateCameraLeft()
{
  angleThetaCam+=0.02;
  updateCamera();
  glutPostRedisplay();
}

//rotate the camera to the right
void rotateCameraRight()
{
  angleThetaCam-=0.02;
  updateCamera();
  glutPostRedisplay();
}

//rotate the camera to the down
void rotateCameraUp()
{
  anglePhiCam+=0.02;
  updateCamera();
  glutPostRedisplay();
}

//rotate the camera to the up
void rotateCameraDown()
{
  anglePhiCam-=0.02;
  updateCamera();
  glutPostRedisplay();
}

//zoom in
void moveCameraAway(float fraction)
{
  distCam*=1.01;
  updateCamera();
  glutPostRedisplay();
}

//zoom in
void moveCameraNearer(float fraction)
{
  distCam/=1.01;
  updateCamera();
  glutPostRedisplay();
}

void processNormalKeys(unsigned char key,int x,int y)
{
  if(key==27) exit(0);
}

void processSpecialKeys(int key,int xx,int yy)
{
  switch(key)
    {
    case GLUT_KEY_LEFT: rotateCameraLeft();break;
    case GLUT_KEY_RIGHT:rotateCameraRight();break;
    case GLUT_KEY_UP:   rotateCameraUp();break;
    case GLUT_KEY_DOWN: rotateCameraDown();break;
    case GLUT_KEY_F1:   moveCameraAway(0.1);break;
    case GLUT_KEY_F2:   moveCameraNearer(0.1);break;
    }
}

void initOpenGL(int &narg,char **arg,void mainFunction())
{
  //init GLUT and create window
  glutInit(&narg,arg);
  glutInitDisplayMode(GLUT_DEPTH|GLUT_DOUBLE|GLUT_RGBA);
  glutInitWindowPosition(100,100);
  glutInitWindowSize(640,640);
  glutCreateWindow("Lighthouse3D - GLUT Tutorial");
  
  updateCamera();
  
  //register callbacks
  glutDisplayFunc(drawSystem);
  glutReshapeFunc(changeSize);
  glutIdleFunc(mainFunction);
  glutKeyboardFunc(processNormalKeys);
  glutSpecialFunc(processSpecialKeys);
  
  //OpenGL init
  glEnable(GL_DEPTH_TEST);
  
  //enter GLUT event processing cycle
  glutMainLoop();
}
